﻿using System.Collections;

namespace Devil
{
    public static partial class ParallelUtils
    {
        public static ParallelDispatcher.CombinedHandler NewCombination(string info = null)
        {
            return new ParallelDispatcher.CombinedHandler(info);
        }

        public static ParallelDispatcher.Handler GetParallelHandler(this object target)
        {
            //if (target is ParallelDispatcher.Handler)
            //    return (ParallelDispatcher.Handler)target;
            //else 
            if (target is ICommandHandler)
                return ((ICommandHandler)target).GetHandler();
            else
                return default;
        }

        public static ParallelDispatcher.Handler Combine(ParallelDispatcher.Handler cmd1, ParallelDispatcher.Handler cmd2)
        {
            if (!cmd2.IsValid)
                return cmd1;
            if (!cmd1.IsValid)
                return cmd2;
#if UNITY_EDITOR
            var combine = new ParallelDispatcher.CombinedHandler(string.Format("{0}+{1}", cmd1, cmd2));
#else
            var combine = new ParallelDispatcher.CombinedHandler("default");
#endif
            combine.Combine(cmd1);
            combine.Combine(cmd2);
            return combine.GetHandler();
        }

        public static void Combine(ref this ParallelDispatcher.CombinedHandler combine, object obj)
        {
            if (obj is ICommandHandler)
                combine.Combine(((ICommandHandler)obj).GetHandler());
        }

        public static ParallelDispatcher.Handler Schedule(this ICommand cmd, bool mainThread, ParallelDispatcher.Handler dependent = default)
        {
            return ParallelDispatcher.GetInstance().Schedule(cmd, mainThread, dependent);
        }

        public static ParallelDispatcher.Handler Schedule(this System.Action action, bool mainThread, ParallelDispatcher.Handler dependent = default)
        {
            if (action == null)
                throw new System.ArgumentNullException("action");
            return ParallelDispatcher.GetInstance().Schedule(new Cmd0(action), mainThread, dependent);
        }

        public static ParallelDispatcher.Handler Schedule<T>(this System.Action<T> action, T arg, bool mainThread, ParallelDispatcher.Handler dependent = default)
        {
            if (action == null)
                throw new System.ArgumentNullException("action");
            return ParallelDispatcher.GetInstance().Schedule(new Cmd1<T>(action, arg), mainThread, dependent);
        }

        public static ParallelDispatcher.Handler Schedule(this IYieldCommand cmd, bool mainThread, ParallelDispatcher.Handler dependent = default)
        {
            return ParallelDispatcher.GetInstance().Schedule(cmd, mainThread, dependent);
        }

        public static ParallelDispatcher.Handler Schedule(this YieldAction action, bool mainThread, ParallelDispatcher.Handler dependent = default)
        {
            if (action == null)
                throw new System.ArgumentNullException("action");
            return ParallelDispatcher.GetInstance().Schedule(new CmdYield(action), mainThread, dependent);
        }

        public static ParallelDispatcher.Handler Schedule<T>(this YieldAction<T> action, T arg, bool mainThread, ParallelDispatcher.Handler dependent = default)
        {
            if (action == null)
                throw new System.ArgumentNullException("action");
            return ParallelDispatcher.GetInstance().Schedule(new CmdYield1<T>(action, arg), mainThread, dependent);
        }

        public static ParallelDispatcher.Handler Schedule<T>(this ICommandParallelFor<T> parallel, IEnumerable iter, ParallelDispatcher.Handler dependent = default)
        {
            return ParallelDispatcher.GetInstance().Schedule(parallel, iter, dependent);
        }

        public static ParallelDispatcher.Handler Schedule(this ICommandParallelFor<int> parallel, int count, ParallelDispatcher.Handler dependent = default)
        {
            return ParallelDispatcher.GetInstance().Schedule(parallel, count, dependent);
        }

        public static ParallelDispatcher.Handler ScheduleParallel<T>(this System.Action<T> action, IEnumerable iter, ParallelDispatcher.Handler dependent = default)
        {
            if (action == null)
                throw new System.ArgumentNullException("action");
            return ParallelDispatcher.GetInstance().Schedule(new CmdParallel<T>(action), iter, dependent);
        }

        public static ParallelDispatcher.Handler ScheduleParallel(this System.Action<int> action, int count, ParallelDispatcher.Handler dependent = default)
        {
            if (action == null)
                throw new System.ArgumentNullException("action");
            return ParallelDispatcher.GetInstance().Schedule(new CmdParallel<int>(action), count, dependent);
        }

        public static ParallelDispatcher.Handler Schedule(this ILoopCommand cmd, bool mainThread, ParallelDispatcher.Handler dependent = default)
        {
            return ParallelDispatcher.GetInstance().Schedule(cmd, mainThread, dependent);
        }

        public static ParallelDispatcher.Handler ScheduleLooper(this System.Action<float> action, bool mainThread, ParallelDispatcher.Handler dependent = default)
        {
            if (action == null)
                throw new System.ArgumentNullException("action");
            return ParallelDispatcher.GetInstance().Schedule(new CmdLooper(action), mainThread, dependent);
        }
    }

}
